feat(connector): Airtable, PagerDuty, Twilio, and Asana connectors#145
Conversation
#103, #99, #96, #116) Implements eight connector actions across four services: - airtable/list, airtable/create_record - pagerduty/create_incident, pagerduty/resolve - twilio/sms, twilio/call - asana/create_task, asana/search All connectors follow established patterns: dual credential shape (map[string]string + map[string]any), url.PathEscape on user-supplied path segments, io.LimitReader on response bodies, and httptest.Server injection via baseURL for unit testing. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
📝 WalkthroughWalkthroughAdds four new external service connectors to the Mantle engine: Airtable (list and create-record), Asana (create-task and search), PagerDuty (create-incident and resolve), and Twilio (SMS and call). Each connector validates credentials, performs HTTP operations with appropriate auth, enforces expected status codes, and returns normalized response maps. All connectors are registered in the central connector registry. ChangesConnector implementations for Airtable, Asana, PagerDuty, and Twilio
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 964e4d0f70
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
Pull request overview
Adds four new REST connectors — Airtable, PagerDuty, Twilio, and Asana — exposing eight new actions and registering them in the connector registry. Each connector follows the established pattern (path-escaped user inputs, io.LimitReader on responses, dual map[string]string / map[string]any credential handling, baseURL test injection) and ships with unit tests covering happy paths, optional params, missing required params, missing credentials, API errors, and the map[string]any credential shape.
Changes:
- Implement Airtable, PagerDuty, Twilio, and Asana connectors (8 actions total) with consistent credential/error/response handling.
- Register all 8 new actions in
NewRegistry(). - Add ~49 unit tests using
httptest.NewServerand unexportedbaseURLinjection.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/engine/internal/connector/connector.go | Registers the 8 new connector actions in the default registry. |
| packages/engine/internal/connector/airtable.go | Implements airtable/list and airtable/create_record with PAT bearer auth and optional list query params. |
| packages/engine/internal/connector/airtable_test.go | Unit tests for both Airtable connectors, including pagination offset and map[string]any credentials. |
| packages/engine/internal/connector/pagerduty.go | Implements pagerduty/create_incident and pagerduty/resolve with token auth and optional From header. |
| packages/engine/internal/connector/pagerduty_test.go | Unit tests covering required params, optional details/urgency, from_email handling, and error cases. |
| packages/engine/internal/connector/twilio.go | Implements twilio/sms and twilio/call using Basic auth and form-encoded bodies. |
| packages/engine/internal/connector/twilio_test.go | Tests for SMS, call (with url and with twiml), missing-param/credential paths, and SID-in-URL escaping. |
| packages/engine/internal/connector/asana.go | Implements asana/create_task (workspace or projects) and asana/search (text/assignee/completed/limit filters). |
| packages/engine/internal/connector/asana_test.go | Tests for both Asana connectors including optional fields, filters, and map[string]any credentials. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- pagerduty/resolve: make from_email required (PagerDuty rejects PUT /incidents without a From header when using REST API keys); accepted from credential or as an explicit param - twilio/call: error when both url and twiml are supplied (mutually exclusive) - asana/create_task: use toStringSlice for projects so []string and []any are both accepted without a silent nil fallback Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
🧹 Nitpick comments (1)
packages/engine/internal/connector/asana.go (1)
191-211: ⚡ Quick winConsider consolidating the duplicated bearer-token extractor.
extractAsanaTokenis byte-for-byte identical toextractAirtableTokeninairtable.go. As more connectors follow this Bearer-token pattern, a single shared helper (e.g.extractBearerToken) would reduce drift risk.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/engine/internal/connector/asana.go` around lines 191 - 211, The Asana token extractor duplicates logic from Airtable; create a shared helper function named extractBearerToken(params map[string]any) (string, error) that performs the common steps (read and delete "_credential" from params, accept both map[string]string and map[string]any, extract "token" string, and return an error if missing), then replace extractAsanaToken and extractAirtableToken to call extractBearerToken and return its result (or remove the duplicates and update callers to use extractBearerToken); ensure the helper preserves the current behavior of deleting "_credential" from params and returns the same error messages when token is missing.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@packages/engine/internal/connector/asana.go`:
- Around line 191-211: The Asana token extractor duplicates logic from Airtable;
create a shared helper function named extractBearerToken(params map[string]any)
(string, error) that performs the common steps (read and delete "_credential"
from params, accept both map[string]string and map[string]any, extract "token"
string, and return an error if missing), then replace extractAsanaToken and
extractAirtableToken to call extractBearerToken and return its result (or remove
the duplicates and update callers to use extractBearerToken); ensure the helper
preserves the current behavior of deleting "_credential" from params and returns
the same error messages when token is missing.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: d8d8e5de-9b28-4ac1-9b50-462e19b6bb78
📒 Files selected for processing (9)
packages/engine/internal/connector/airtable.gopackages/engine/internal/connector/airtable_test.gopackages/engine/internal/connector/asana.gopackages/engine/internal/connector/asana_test.gopackages/engine/internal/connector/connector.gopackages/engine/internal/connector/pagerduty.gopackages/engine/internal/connector/pagerduty_test.gopackages/engine/internal/connector/twilio.gopackages/engine/internal/connector/twilio_test.go
Summary
Implements 8 connector actions across 4 REST services, closing issues #103, #99, #96, and #116.
airtable/listmax_records,filter_by_formula,view,offsetairtable/create_recordfieldspagerduty/create_incidenturgency,details,from_emailpagerduty/resolvetwilio/smstwilio/callurlortwimlasana/create_tasknotes,assignee,due_onasana/searchtext,assignee,completed,limitAll connectors follow the established patterns from existing connectors:
map[string]string+map[string]any)url.PathEscapeon all user-supplied path segmentsio.LimitReader(resp.Body, DefaultMaxResponseBytes)on all responsesbaseURLfield forhttptest.Serverinjection in tests_credentialdeleted from params after extractionTest plan
go test ./internal/connector/...)map[string]anycredential shape coverageCloses #103, #99, #96, #116
🤖 Generated with Claude Code
Summary by CodeRabbit
Release Notes
New Features